diff -Naur linux-2.6.2/drivers/net/wireless/airport.c linux-2.6.2-orinoco/drivers/net/wireless/airport.c --- linux-2.6.2/drivers/net/wireless/airport.c 2003-12-18 10:59:45.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/airport.c 2004-02-17 15:26:40.000000000 +0800 @@ -16,24 +16,26 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include #include #include #include #include +#include +#include -#include -#include -#include #include #include #include #include -#include #include "orinoco.h" @@ -46,115 +48,96 @@ int ndev_registered; }; -static int -airport_suspend(struct macio_dev *mdev, u32 state) -{ - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; - struct airport *card = priv->card; - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", - dev->name); - return 0; - } - - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; +#ifdef CONFIG_PMAC_PBOOK +static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier airport_sleep_notifier = { + airport_sleep_notify, SLEEP_LEVEL_NET, +}; +#endif - orinoco_unlock(priv, &flags); +/* + * Function prototypes + */ - disable_irq(dev->irq); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); +static struct net_device *airport_attach(struct device_node *of_node); +static void airport_detach(struct net_device *dev); - return 0; -} +static struct net_device *airport_dev; +#ifdef CONFIG_PMAC_PBOOK static int -airport_resume(struct macio_dev *mdev) +airport_sleep_notify(struct pmu_sleep_notifier *self, int when) { - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); + struct net_device *dev = airport_dev; struct orinoco_private *priv = dev->priv; struct airport *card = priv->card; unsigned long flags; int err; + + if (! airport_dev) + return PBOOK_SLEEP_OK; + + switch (when) { + case PBOOK_SLEEP_NOW: + printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); + + err = orinoco_lock(priv, &flags); + if (err) { + printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", + dev->name); + break; + } - printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", + dev->name, err); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); - mdelay(200); + netif_device_detach(dev); - enable_irq(dev->irq); + priv->hw_unavailable++; - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", - dev->name, err); - return 0; - } + orinoco_unlock(priv, &flags); - spin_lock_irqsave(&priv->lock, flags); + disable_irq(dev->irq); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); + break; - netif_device_attach(dev); + case PBOOK_WAKE: + printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); + mdelay(200); - priv->hw_unavailable--; + enable_irq(dev->irq); - if (priv->open && (! priv->hw_unavailable)) { - err = __orinoco_up(dev); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", dev->name, err); - } + break; + } + spin_lock_irqsave(&priv->lock, flags); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static int -airport_detach(struct macio_dev *mdev) -{ - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; - struct airport *card = priv->card; + netif_device_attach(dev); - if (card->ndev_registered) - unregister_netdev(dev); - card->ndev_registered = 0; + priv->hw_unavailable--; - if (card->irq_requested) - free_irq(dev->irq, dev); - card->irq_requested = 0; + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", + dev->name, err); + } - if (card->vaddr) - iounmap(card->vaddr); - card->vaddr = 0; - dev->base_addr = 0; + spin_unlock_irqrestore(&priv->lock, flags); - release_OF_resource(card->node, 0); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); - - dev_set_drvdata(&mdev->ofdev.dev, NULL); - free_netdev(dev); - - return 0; + break; + } + return PBOOK_SLEEP_OK; } +#endif /* CONFIG_PMAC_PBOOK */ static int airport_hard_reset(struct orinoco_private *priv) { @@ -187,26 +170,25 @@ return 0; } -static int -airport_attach(struct macio_dev *mdev, const struct of_match *match) +static struct net_device * +airport_attach(struct device_node *of_node) { struct orinoco_private *priv; struct net_device *dev; struct airport *card; unsigned long phys_addr; - struct device_node *of_node = mdev->ofdev.node; hermes_t *hw; if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); - return -ENODEV; + return NULL; } /* Allocate space for private device-specific data */ dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); if (! dev) { printk(KERN_ERR "airport: can't allocate device datas\n"); - return -ENODEV; + return NULL; } priv = dev->priv; card = priv->card; @@ -217,14 +199,11 @@ if (! request_OF_resource(of_node, 0, " (airport)")) { printk(KERN_ERR "airport: can't request IO resource !\n"); kfree(dev); - return -ENODEV; + return NULL; } dev->name[0] = '\0'; /* register_netdev will give us an ethX name */ SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - - dev_set_drvdata(&mdev->ofdev.dev, dev); /* Setup interrupts & base address */ dev->irq = of_node->intrs[0].line; @@ -261,50 +240,79 @@ } printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name); card->ndev_registered = 1; - return 0; + +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&airport_sleep_notifier); +#endif + return dev; + failed: - airport_detach(mdev); - return -ENODEV; + airport_detach(dev); + return NULL; } /* airport_attach */ +/*====================================================================== + This deletes a driver "instance". + ======================================================================*/ + +static void +airport_detach(struct net_device *dev) +{ + struct orinoco_private *priv = dev->priv; + struct airport *card = priv->card; + +#ifdef CONFIG_PMAC_PBOOK + pmu_unregister_sleep_notifier(&airport_sleep_notifier); +#endif + if (card->ndev_registered) + unregister_netdev(dev); + card->ndev_registered = 0; + + if (card->irq_requested) + free_irq(dev->irq, dev); + card->irq_requested = 0; + + if (card->vaddr) + iounmap(card->vaddr); + card->vaddr = 0; + + dev->base_addr = 0; + + release_OF_resource(card->node, 0); + + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + kfree(dev); +} /* airport_detach */ static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt )"; MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); -static struct of_match airport_match[] = -{ - { - .name = "radio", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH - }, - {}, -}; - -static struct macio_driver airport_driver = -{ - .name = "airport", - .match_table = airport_match, - .probe = airport_attach, - .remove = airport_detach, - .suspend = airport_suspend, - .resume = airport_resume, -}; - static int __init init_airport(void) { + struct device_node *airport_node; + printk(KERN_DEBUG "%s\n", version); - return macio_register_driver(&airport_driver); + /* Lookup card in device tree */ + airport_node = find_devices("radio"); + if (airport_node && !strcmp(airport_node->parent->name, "mac-io")) + airport_dev = airport_attach(airport_node); + + return airport_dev ? 0 : -ENODEV; } static void __exit exit_airport(void) { - return macio_unregister_driver(&airport_driver); + if (airport_dev) + airport_detach(airport_dev); + airport_dev = NULL; } module_init(init_airport); diff -Naur linux-2.6.2/drivers/net/wireless/hermes.c linux-2.6.2-orinoco/drivers/net/wireless/hermes.c --- linux-2.6.2/drivers/net/wireless/hermes.c 2003-12-18 10:58:16.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/hermes.c 2004-02-17 15:26:40.000000000 +0800 @@ -183,6 +183,10 @@ if (err) return err; + for ( k = 0; k < HERMES_NUMPORTS_MAX; k++) { + hw->port_enabled[k] = 0; + } + reg = hermes_read_regn(hw, EVSTAT); k = CMD_INIT_TIMEOUT; while ( (! (reg & HERMES_EV_CMD)) && k) { diff -Naur linux-2.6.2/drivers/net/wireless/hermes.conf linux-2.6.2-orinoco/drivers/net/wireless/hermes.conf --- linux-2.6.2/drivers/net/wireless/hermes.conf 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/hermes.conf 2004-02-17 15:26:40.000000000 +0800 @@ -0,0 +1,118 @@ +device "orinoco_cs" + class "network" + module "hermes", "orinoco", "orinoco_cs" +# module "hermes", "orinoco", "orinoco_cs" opts "pc_debug=3" + +# +# Wireless network adapters +# +# We should use the manfid (which cover multiple cards), otherwise we will +# go crazy listing all cards and their variations !!! + +# First class of device : Lucent & OEM +card "Orinoco or Intersil Prism 2 Wireless" + manfid 0x0156,0x0002 + bind "orinoco_cs" + +card "Lucent Technologies Wavelan/IEEE" + version "Lucent Technologies", "WaveLAN/IEEE" + bind "orinoco_cs" + +card "Avaya World Card" + version "Avaya Communication", "Avaya Wireless PC Card" + bind "orinoco_cs" + +card "Cabletron RoamAbout 802.11 DS" + version "Cabletron", "RoamAbout 802.11 DS" + bind "orinoco_cs" + +card "ELSA AirLancer MC-11" + version "ELSA", "AirLancer MC-11" + bind "orinoco_cs" + +card "MELCO WLI-PCM-L11" + version "MELCO", "WLI-PCM-L11" + bind "orinoco_cs" + +# Second class of device : Symbol & OEM +card "LA4111 Spectrum24 Wireless LAN PC Card" + version "Symbol Technologies" + bind "orinoco_cs" + +card "3Com AirConnect" + version "3Com", "3CRWE737A AirConnect Wireless LAN PC Card" + bind "orinoco_cs" + +card "Intel PRO/Wireless 2011" + manfid 0x0089,0x0001 + bind "orinoco_cs" + +card "Ericsson WLAN Card C11" + manfid 0x016b,0x0001 + bind "orinoco_cs" + +card "Nortel Networks e-mobility 802.11 Wireless LAN PC Card" + version "Nortel Networks", "emobility 802.11 Wireless LAN PC Card", "1.00" + bind "orinoco_cs" + +card "D-Link DWL-650H" + version "D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter" + bind "orinoco_cs" + +# Third class of device : other Intersil clones +card "Farallon SkyLINE" + version "INTERSIL", "HFA384x/IEEE" + bind "orinoco_cs" + +card "D-Link DWL-650" + version "D", "Link DWL-650 11Mbps WLAN Card" + bind "orinoco_cs" + +card "SAMSUNG 11Mbps WLAN Card" + version "SAMSUNG", "11Mbps WLAN Card" + bind "orinoco_cs" +# Does this one cover Compaq as well ??? + +card "HyperLink Wireless PC Card 11Mbps" + version "HyperLink","Wireless PC Card 11Mbps" + bind "orinoco_cs" + +card "PROXIM LAN PC CARD HARMONY 80211B" + version "PROXIM","LAN PC CARD HARMONY 80211B" + bind "orinoco_cs" + +card "Linksys WPC11 11Mbps 802.11b WLAN Card" + version "Instant Wireless ", " Network PC CARD", "Version 01.02" + bind "orinoco_cs" + +card "Linksys WPC11 11Mbps 802.11b WLAN Card" + version "The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", "RevA" + bind "orinoco_cs" + +card "Linksys CompactFlash Wireless Card" + version "Linksys", "Wireless CompactFlash Card" + bind "orinoco_cs" + +card "Tekram PCF-200" + version "PCMCIA", "11M WLAN Card v2.5", "ISL37300P", "RevA" + bind "orinoco_cs" + +card "ACTIONTEC PRISM Wireless LAN PC Card" + version "ACTIONTEC", "PRISM Wireless LAN PC Card" + bind "orinoco_cs" + +card "Zcomax XI-325HP" + version " ", "IEEE 802.11 Wireless LAN/PC Card" + bind "orinoco_cs" + +card "Microsoft Wireless Notebook Adapter MN-520 1.0.3" + version "Microsoft", "Wireless Notebook Adapter MN-520", "", "1.0.3" + bind "orinoco_cs" + +card "Linksys WPC11 Version 3" + manfid 0x0274,0x1613 + bind "orinoco_cs" + +card "Netgear MA401RA" + version "NETGEAR MA401RA Wireless PC", "Card", "ISL37300P", "Eval-RevA" + bind "orinoco_cs" diff -Naur linux-2.6.2/drivers/net/wireless/hermes.h linux-2.6.2-orinoco/drivers/net/wireless/hermes.h --- linux-2.6.2/drivers/net/wireless/hermes.h 2003-12-18 10:58:08.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/hermes.h 2004-02-17 15:26:40.000000000 +0800 @@ -33,6 +33,10 @@ #include #include +#define HFA384x_PORTTYPE_IBSS ((uint16_t)3) +#define HFA384x_WEPFLAGS_DISABLE_TXCRYPT (0x10) +#define HFA384x_WEPFLAGS_DISABLE_RXCRYPT (0x80) + /* * Limits and constants */ @@ -149,6 +153,38 @@ #define HERMES_MONITOR_DISABLE (0x000f) /* + * Configuration RIDs + */ + +#define HERMES_RID_CNF_PORTTYPE (0xfc00) +#define HERMES_RID_CNF_CHANNEL (0xfc03) +#define HERMES_RID_CNF_PRISM2_WEP_ON (0xfc28) + +/*-- Status Fields --*/ +#define HERMES_RXSTATUS_MSGTYPE (0xE000) +#define HERMES_RXSTATUS_MACPORT (0x0700) +#define HERMES_RXSTATUS_UNDECR (0x0002) +#define HERMES_RXSTATUS_FCSERR (0x0001) + +/*-------------------------------------------------------------------- +Communication Frames: Test/Get/Set Field Values for Receive Frames +--------------------------------------------------------------------*/ +#define HERMES_RXSTATUS_MSGTYPE_GET(value) (((value) & HERMES_RXSTATUS_MSGTYPE) >> 13) +#define HERMES_RXSTATUS_MSGTYPE_SET(value) ((value) << 13) +#define HERMES_RXSTATUS_MACPORT_GET(value) (((value) & HERMES_RXSTATUS_MACPORT) >> 8) +#define HERMES_RXSTATUS_MACPORT_SET(value) ((value) << 8) +#define HERMES_RXSTATUS_ISUNDECR(value) ((value) & HERMES_RXSTATUS_UNDECR) +#define HERMES_RXSTATUS_ISFCSERR(value) ((value) & HERMES_RXSTATUS_FCSERR) + +/*-------------------------------------------------------------------- +Communication Frames: Field Masks for Receive Frames +--------------------------------------------------------------------*/ +/*-- Offsets --------*/ +#define HERMES_RX_DATA_LEN_OFF (44) +#define HERMES_RX_80211HDR_OFF (14) +#define HERMES_RX_DATA_OFF (60) + +/* * Frame structures and constants */ @@ -286,6 +322,7 @@ #define HERMES_32BIT_REGSPACING 1 u16 inten; /* Which interrupts should be enabled? */ + uint8_t port_enabled[HERMES_NUMPORTS_MAX]; #ifdef HERMES_DEBUG_BUFFER struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE]; @@ -302,14 +339,12 @@ #define hermes_read_reg(hw, off) ((hw)->io_space ? \ inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \ readw((hw)->iobase + ( (off) << (hw)->reg_spacing ))) -#define hermes_write_reg(hw, off, val) do { \ - if ((hw)->io_space) \ - outw_p((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \ - else \ - writew((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \ - } while (0) -#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) -#define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val)) +#define hermes_write_reg(hw, off, val) ((hw)->io_space ? \ + outw_p((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )) : \ + writew((val), (hw)->iobase + ( (off) << (hw)->reg_spacing ))) + +#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) +#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) /* Function prototypes */ void hermes_struct_init(hermes_t *hw, ulong address, int io_space, int reg_spacing); @@ -341,12 +376,14 @@ static inline int hermes_enable_port(hermes_t *hw, int port) { + hw->port_enabled[port] = 1; return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), 0, NULL); } static inline int hermes_disable_port(hermes_t *hw, int port) { + hw->port_enabled[port] = 0; return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 0, NULL); } diff -Naur linux-2.6.2/drivers/net/wireless/orinoco.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco.c --- linux-2.6.2/drivers/net/wireless/orinoco.c 2003-12-18 11:00:00.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco.c 2004-02-17 15:26:40.000000000 +0800 @@ -458,6 +458,7 @@ #endif static int suppress_linkstatus; /* = 0 */ +static int suppress_linkstatus_copy; /* = 0 */ MODULE_PARM(suppress_linkstatus, "i"); /********************************************************************/ @@ -1673,6 +1674,7 @@ struct header_struct hdr; struct ethhdr *eh; int err; + struct ieee802_11_hdr hdr80211; rxfid = hermes_read_regn(hw, RXFID); @@ -1689,6 +1691,7 @@ if (status & HERMES_RXSTAT_ERR) { if (status & HERMES_RXSTAT_UNDECRYPTABLE) { + if (dev->type != ARPHRD_ETHER) goto sniffing; wstats->discard.code++; DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", dev->name); @@ -1699,7 +1702,7 @@ stats->rx_errors++; goto drop; } - +sniffing: /* For now we ignore the 802.11 header completely, assuming that the card's firmware has handled anything vital */ @@ -1730,6 +1733,11 @@ goto drop; } + /* Now handle frame based on port# */ + switch( HERMES_RXSTATUS_MACPORT_GET(status) ) + { + case 0: + /* We need space for the packet data itself, plus an ethernet header, plus 2 bytes so we can align the IP header on a 32bit boundary, plus 1 byte so we can read in odd length @@ -1804,6 +1812,26 @@ return; + case 7: + if ( ! HERMES_RXSTATUS_ISFCSERR(status) ) { + if (hermes_bap_pread(hw, IRQ_BAP, &hdr80211, sizeof(hdr80211), + rxfid, HERMES_RX_80211HDR_OFF)) { + stats->rx_errors++; + } + else { + /* Copy to wlansnif skb */ + orinoco_int_rxmonitor( priv, rxfid, length, &desc, &hdr80211); + } + } else { + printk("Received monitor frame: FCSerr set\n"); + } + break; + default: + printk("Received frame on unsupported port=%d\n", + HERMES_RXSTATUS_MACPORT_GET(status) ); + break; + } + drop: stats->rx_dropped++; @@ -2446,6 +2474,24 @@ return err; } +//#define SET_MAC_ADDRESS +#ifdef SET_MAC_ADDRESS +static int +orinoco_set_mac_address(struct net_device *dev, void *addr) +{ + struct orinoco_private *priv = dev->priv; + struct sockaddr *mac = addr; + + /* Copy the address */ + memcpy(dev->dev_addr, mac->sa_data, WLAN_ADDR_LEN); + + /* Reconfig the beast */ + orinoco_reset(priv); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + static void orinoco_tx_timeout(struct net_device *dev) { @@ -3598,6 +3644,170 @@ return 0; } +/*---------------------------------------------------------------- +* orinoco_wlansniff +* +* Start or stop sniffing. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +static int orinoco_wlansniff(struct net_device *dev, struct iwreq *wrq) +{ + struct orinoco_private *priv = dev->priv; + hermes_t *hw = &(priv->hw); + hermes_response_t resp; + int result = 0; + uint16_t word; + + int *parms = (int *) wrq->u.name; + int enable = parms[0] > 0; + unsigned long flags; + int noMonitor = dev->type != ARPHRD_IEEE80211_PRISM && + dev->type != ARPHRD_IEEE80211; + + orinoco_lock(priv, &flags); + + switch (enable) + { + case P80211ENUM_truth_false: + /* Confirm that we're in monitor mode */ + if ( noMonitor ) { + result = -EFAULT; + } + /* Disable monitor mode */ + suppress_linkstatus = suppress_linkstatus_copy; + word = HERMES_CMD_MONITOR | (HERMES_MONITOR_DISABLE << 8); + result = hermes_docmd_wait(hw, word, 0, &resp); + + if ( result ) break; + + /* Disable port 0 */ + result = hermes_disable_port(hw, 0); + if ( result ) break; + + /* Clear the driver state */ + dev->type = ARPHRD_ETHER; + + /* Restore the wepflags */ //Orinoco doesn't like this +/* + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_WEP_ON, + priv->presniff_wepflags); + if ( result ) break; + +*/ + /* Set the port to its prior type and enable (if necessary) */ + if (priv->presniff_port_type != 0 ) { + word = priv->presniff_port_type; + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PORTTYPE, word); + if ( result ) break; + + /* Enable the port */ + result = hermes_enable_port(hw, 0); + if ( result ) break; + + } + + break; + case P80211ENUM_truth_true: + // Only do this if we're not in monitor mode already + if (noMonitor) { + /* Re-initialize the card before changing channel as advised at + * http://lists.samba.org/pipermail/wireless/2002-June/004491.html + * by Ian Goldberg. Implementation by Pat Swieskowski. + */ + // __orinoco_down(dev); + hermes_set_irqmask(hw, 0); + hermes_init(hw); + // _orinoco_up(dev); + hermes_set_irqmask(hw, ORINOCO_INTEN); + suppress_linkstatus = 1; + /* + __orinoco_stop_irqs(priv); + hermes_reset(hw); + __orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + HERMES_EV_TX | HERMES_EV_TXEXC | + HERMES_EV_WTERR | HERMES_EV_INFO | + HERMES_EV_INFDROP); + */ + /* Disable the port (if enabled), only check Port 0 */ + if ( hw->port_enabled[0] ) { + /* Save macport 0 state */ + result = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PORTTYPE, + &(priv->presniff_port_type)); + if ( result ) break; + + /* Save the wepflags state */ + result = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_WEP_ON, + &(priv->presniff_wepflags)); + if ( result ) break; + } + else { + priv->presniff_port_type = 0; + } + } + + // Disable the port + result = hermes_disable_port(hw, 0); + if ( result ) break; + + /* Set the channel we wish to sniff */ + if (parms[1] > 0 && parms[1] < 15) { + word = parms[1]; + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_CHANNEL, word); + } else { + result = -EFAULT; + } + + if ( result ) break; + + if (noMonitor) { + /* Set the port type to pIbss */ + word = HFA384x_PORTTYPE_IBSS; + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PORTTYPE, word); + if ( result ) break; + + /* Enable monitor mode */ + word = HERMES_CMD_MONITOR | (HERMES_MONITOR_ENABLE << 8); + result = hermes_docmd_wait(hw, word, 0, &resp); + if ( result ) break; + } + + /* Enable the port */ + result = hermes_enable_port(hw, 0); + if ( result ) break; + /* Set the driver state */ + /* Do we want the prism2 header? */ + if (parms[0] == 1) + dev->type = ARPHRD_IEEE80211_PRISM; + else + dev->type = ARPHRD_IEEE80211; + break; + default: + result = -EFAULT; + break; + } + orinoco_unlock(priv, &flags); + return result; +} + static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -3830,9 +4040,16 @@ { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_ibssport" }, + { SIOCIWFIRSTPRIV + 0x8, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "monitor" }, { SIOCIWLASTPRIV, 0, 0, "dump_recs" }, }; + err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); + if (err) + break; + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) err = -EFAULT; @@ -3920,6 +4137,16 @@ err = orinoco_ioctl_getibssport(dev, wrq); break; + case SIOCIWFIRSTPRIV + 0x8: /* set sniff (monitor) mode */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x8 (monitor)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + err = orinoco_wlansniff(dev, wrq); + break; + case SIOCIWLASTPRIV: err = orinoco_debug_dump_recs(dev); if (err) @@ -4142,6 +4369,9 @@ dev->tx_timeout = orinoco_tx_timeout; dev->watchdog_timeo = HZ; /* 1 second timeout */ dev->get_stats = orinoco_get_stats; +#ifdef SET_MAC_ADDRESS + dev->set_mac_address = orinoco_set_mac_address; +#endif /* SET_MAC_ADDRESS */ dev->get_wireless_stats = orinoco_get_wireless_stats; dev->do_ioctl = orinoco_ioctl; dev->change_mtu = orinoco_change_mtu; @@ -4167,6 +4397,197 @@ } +/*---------------------------------------------------------------- +* orinoco_int_rxmonitor +* +* Helper function for int_rx. Handles monitor frames. +* Note that this function allocates space for the FCS and sets it +* to 0xffffffff. The hfa384x doesn't give us the FCS value but the +* higher layers expect it. 0xffffffff is used as a flag to indicate +* the FCS is bogus. +* +* Arguments: +* dev wlan device structure +* rxfid received FID +* rxdesc rx descriptor read from card in int_rx +* +* Returns: +* nothing +* +* Side effects: +* Allocates an skb and passes it up via the PF_PACKET interface. +* Call context: +* interrupt +----------------------------------------------------------------*/ +void orinoco_int_rxmonitor( struct orinoco_private *dev, uint16_t rxfid, int len, + struct hermes_rx_descriptor *rxdesc, struct ieee802_11_hdr *hdr) +{ + hermes_t *hw = &(dev->hw); + uint32_t hdrlen = 0; + uint32_t datalen = 0; + uint32_t skblen = 0; + p80211msg_lnxind_wlansniffrm_t *msg; + struct net_device_stats *stats = &dev->stats; + + + uint8_t *datap; + uint16_t fc; + struct sk_buff *skb; + + /* Don't forget the status, time, and data_len fields are in host order */ + /* Figure out how big the frame is */ + fc = le16_to_cpu(hdr->frame_ctl); + switch ( WLAN_GET_FC_FTYPE(fc) ) + { + case WLAN_FTYPE_DATA: + if ( WLAN_GET_FC_TODS(fc) && WLAN_GET_FC_FROMDS(fc) ) { + hdrlen = WLAN_HDR_A4_LEN; + } else { + hdrlen = WLAN_HDR_A3_LEN; + } + datalen = len; + break; + case WLAN_FTYPE_MGMT: + hdrlen = WLAN_HDR_A3_LEN; + datalen = len; + break; + case WLAN_FTYPE_CTL: + switch ( WLAN_GET_FC_FSTYPE(fc) ) + { + case WLAN_FSTYPE_PSPOLL: + case WLAN_FSTYPE_RTS: + case WLAN_FSTYPE_CFEND: + case WLAN_FSTYPE_CFENDCFACK: + hdrlen = 16; + break; + case WLAN_FSTYPE_CTS: + case WLAN_FSTYPE_ACK: + hdrlen = 10; + break; + } + datalen = 0; + break; + default: + printk("unknown frm: fc=0x%04x\n", fc); + return; + } + + /* Allocate an ind message+framesize skb */ + skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + + hdrlen + datalen; + + /* sanity check the length */ + if ( skblen > + (sizeof(p80211msg_lnxind_wlansniffrm_t) + + WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) { + printk("overlen frm: len=%d\n", + skblen - sizeof(p80211msg_lnxind_wlansniffrm_t)); + } + + if ( (skb = dev_alloc_skb(skblen)) == NULL ) { + printk("alloc_skb failed trying to allocate %d bytes\n", skblen); + return; + } + + /* only prepend the prism header if in the right mode */ + if (dev->ndev->type != ARPHRD_IEEE80211_PRISM) { + skb_put(skb, skblen - sizeof(p80211msg_lnxind_wlansniffrm_t)); + datap = skb->data; + } else { + skb_put(skb, skblen); + datap = skb->data + sizeof(p80211msg_lnxind_wlansniffrm_t); + msg = (p80211msg_lnxind_wlansniffrm_t*)skb->data; + + /* Initialize the message members */ + msg->msgcode = DIDmsg_lnxind_wlansniffrm; + msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t); + strcpy(msg->devname, dev->ndev->name); + + msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; + msg->hosttime.status = 0; + msg->hosttime.len = 4; + msg->hosttime.data = jiffies; + + msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; + msg->mactime.status = 0; + msg->mactime.len = 4; + msg->mactime.data = rxdesc->time; + + msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel; + msg->channel.status = P80211ENUM_msgitem_status_no_value; + msg->channel.len = 4; + msg->channel.data = 0; + + msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; + msg->rssi.status = P80211ENUM_msgitem_status_no_value; + msg->rssi.len = 4; + msg->rssi.data = 0; + + msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq; + msg->sq.status = P80211ENUM_msgitem_status_no_value; + msg->sq.len = 4; + msg->sq.data = 0; + + msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal; + msg->signal.status = 0; + msg->signal.len = 4; + msg->signal.data = rxdesc->signal; + + msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise; + msg->noise.status = 0; + msg->noise.len = 4; + msg->noise.data = rxdesc->silence; + + msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate; + msg->rate.status = 0; + msg->rate.len = 4; + msg->rate.data = rxdesc->rate / 5; /* set to 802.11 units */ + + msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx; + msg->istx.status = 0; + msg->istx.len = 4; + msg->istx.data = P80211ENUM_truth_false; + + msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; + msg->frmlen.status = 0; + msg->frmlen.len = 4; + msg->frmlen.data = hdrlen + datalen; + } + + /* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */ + memcpy( datap, &(hdr->frame_ctl), hdrlen); + + /* If any, copy the data from the card to the skb */ + if ( datalen > 0 ) + { + hermes_bap_pread(hw, IRQ_BAP, datap + hdrlen, (datalen+1)&~1, + rxfid, HERMES_RX_DATA_OFF); + + /* check for unencrypted stuff if WEP bit set. */ + if (*(datap+1) & 0x40) // wep set + if ((*(datap+hdrlen) == 0xaa) && (*(datap+hdrlen+1) == 0xaa)) + *(datap+1) &= 0xbf; // clear wep; it's the 802.2 header! + } + + /* pass it up via the PF_PACKET interface */ + { + skb->dev = dev->ndev; + skb->dev->last_rx = jiffies; + + skb->mac.raw = skb->data ; + skb->ip_summed = CHECKSUM_NONE; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); /* XXX ETH_P_802_2? */ + + stats->rx_packets++; + stats->rx_bytes += skb->len; + + netif_rx(skb); + } + + return; +} + /********************************************************************/ /* Module initialization */ /********************************************************************/ @@ -4187,6 +4608,7 @@ static int __init init_orinoco(void) { printk(KERN_DEBUG "%s\n", version); + suppress_linkstatus_copy = suppress_linkstatus; return 0; } diff -Naur linux-2.6.2/drivers/net/wireless/orinoco.h linux-2.6.2-orinoco/drivers/net/wireless/orinoco.h --- linux-2.6.2/drivers/net/wireless/orinoco.h 2003-12-18 10:58:39.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco.h 2004-02-17 15:26:40.000000000 +0800 @@ -37,6 +37,20 @@ /* To enable debug messages */ //#define ORINOCO_DEBUG 3 +#ifndef ETH_P_ECONET +#define ETH_P_ECONET 0x0018 /* needed for 2.2.x kernels */ +#endif + +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) + +#ifndef ARPHRD_IEEE80211 +#define ARPHRD_IEEE80211 801 /* kernel 2.4.6 */ +#endif + +#ifndef ARPHRD_IEEE80211_PRISM /* kernel 2.4.18 */ +#define ARPHRD_IEEE80211_PRISM 802 +#endif + #if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) #error "orinoco driver requires Wireless extensions v10 or later." #endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ @@ -54,6 +68,158 @@ HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \ HERMES_EV_INFDROP ) +#define WLAN_DEVNAMELEN_MAX 16 + +/* message data item for INT, BOUNDEDINT, ENUMINT */ +typedef struct p80211item_uint32 +{ + uint32_t did __attribute__ ((packed)); + uint16_t status __attribute__ ((packed)); + uint16_t len __attribute__ ((packed)); + uint32_t data __attribute__ ((packed)); +} __attribute__ ((packed)) p80211item_uint32_t; + +typedef struct p80211msg +{ + uint32_t msgcode __attribute__ ((packed)); + uint32_t msglen __attribute__ ((packed)); + uint8_t devname[WLAN_DEVNAMELEN_MAX] __attribute__ ((packed)); +} __attribute__ ((packed)) p80211msg_t; + +#define DIDmsg_lnxind_wlansniffrm 0x0041 +#define DIDmsg_lnxind_wlansniffrm_hosttime 0x1041 +#define DIDmsg_lnxind_wlansniffrm_mactime 0x2041 +#define DIDmsg_lnxind_wlansniffrm_channel 0x3041 +#define DIDmsg_lnxind_wlansniffrm_rssi 0x4041 +#define DIDmsg_lnxind_wlansniffrm_sq 0x5041 +#define DIDmsg_lnxind_wlansniffrm_signal 0x6041 +#define DIDmsg_lnxind_wlansniffrm_noise 0x7041 +#define DIDmsg_lnxind_wlansniffrm_rate 0x8041 +#define DIDmsg_lnxind_wlansniffrm_istx 0x9041 +#define DIDmsg_lnxind_wlansniffrm_frmlen 0xA041 + +typedef struct p80211msg_lnxind_wlansniffrm +{ + uint32_t msgcode; + uint32_t msglen; + uint8_t devname[WLAN_DEVNAMELEN_MAX]; + p80211item_uint32_t hosttime; + p80211item_uint32_t mactime; + p80211item_uint32_t channel; + p80211item_uint32_t rssi; + p80211item_uint32_t sq; + p80211item_uint32_t signal; + p80211item_uint32_t noise; + p80211item_uint32_t rate; + p80211item_uint32_t istx; + p80211item_uint32_t frmlen; +} __attribute__ ((packed)) p80211msg_lnxind_wlansniffrm_t; + +#define P80211ENUM_truth_false 0 +#define P80211ENUM_truth_true 1 +#define P80211ENUM_resultcode_success 1 +#define P80211ENUM_resultcode_invalid_parameters 2 +#define P80211ENUM_resultcode_not_supported 3 +#define P80211ENUM_resultcode_timeout 4 +#define P80211ENUM_resultcode_too_many_req 5 +#define P80211ENUM_resultcode_refused 6 +#define P80211ENUM_resultcode_bss_already 7 +#define P80211ENUM_resultcode_invalid_access 8 +#define P80211ENUM_resultcode_invalid_mibattribute 9 +#define P80211ENUM_resultcode_cant_set_readonly_mib 10 +#define P80211ENUM_resultcode_implementation_failure 11 +#define P80211ENUM_resultcode_cant_get_writeonly_mib 12 +#define P80211ENUM_msgitem_status_data_ok 0 +#define P80211ENUM_msgitem_status_no_value 1 +#define P80211ENUM_msgitem_status_invalid_itemname 2 +#define P80211ENUM_msgitem_status_invalid_itemdata 3 +#define P80211ENUM_msgitem_status_missing_itemdata 4 +#define P80211ENUM_msgitem_status_incomplete_itemdata 5 +#define P80211ENUM_msgitem_status_invalid_msg_did 6 +#define P80211ENUM_msgitem_status_invalid_mib_did 7 +#define P80211ENUM_msgitem_status_missing_conv_func 8 +#define P80211ENUM_msgitem_status_string_too_long 9 +#define P80211ENUM_msgitem_status_data_out_of_range 10 +#define P80211ENUM_msgitem_status_string_too_short 11 +#define P80211ENUM_msgitem_status_missing_valid_func 12 +#define P80211ENUM_msgitem_status_unknown 13 +#define P80211ENUM_msgitem_status_invalid_did 14 +#define P80211ENUM_msgitem_status_missing_print_func 15 + +#define WLAN_GET_FC_FTYPE(n) (((n) & 0x0C) >> 2) +#define WLAN_GET_FC_FSTYPE(n) (((n) & 0xF0) >> 4) +#define WLAN_GET_FC_TODS(n) (((n) & 0x0100) >> 8) +#define WLAN_GET_FC_FROMDS(n) (((n) & 0x0200) >> 9) + +/*--- Sizes -----------------------------------------------*/ +#define WLAN_ADDR_LEN 6 +#define WLAN_CRC_LEN 4 +#define WLAN_BSSID_LEN 6 +#define WLAN_BSS_TS_LEN 8 +#define WLAN_HDR_A3_LEN 24 +#define WLAN_HDR_A4_LEN 30 +#define WLAN_SSID_MAXLEN 32 +#define WLAN_DATA_MAXLEN 2312 + +/*--- Frame Control Field -------------------------------------*/ +/* Frame Types */ +#define WLAN_FTYPE_MGMT 0x00 +#define WLAN_FTYPE_CTL 0x01 +#define WLAN_FTYPE_DATA 0x02 + +/* Frame subtypes */ +/* Management */ +#define WLAN_FSTYPE_ASSOCREQ 0x00 +#define WLAN_FSTYPE_ASSOCRESP 0x01 +#define WLAN_FSTYPE_REASSOCREQ 0x02 +#define WLAN_FSTYPE_REASSOCRESP 0x03 +#define WLAN_FSTYPE_PROBEREQ 0x04 +#define WLAN_FSTYPE_PROBERESP 0x05 +#define WLAN_FSTYPE_BEACON 0x08 +#define WLAN_FSTYPE_ATIM 0x09 +#define WLAN_FSTYPE_DISASSOC 0x0a +#define WLAN_FSTYPE_AUTHEN 0x0b +#define WLAN_FSTYPE_DEAUTHEN 0x0c + +/* Control */ +#define WLAN_FSTYPE_PSPOLL 0x0a +#define WLAN_FSTYPE_RTS 0x0b +#define WLAN_FSTYPE_CTS 0x0c +#define WLAN_FSTYPE_ACK 0x0d +#define WLAN_FSTYPE_CFEND 0x0e +#define WLAN_FSTYPE_CFENDCFACK 0x0f + +/* Data */ +#define WLAN_FSTYPE_DATAONLY 0x00 +#define WLAN_FSTYPE_DATA_CFACK 0x01 +#define WLAN_FSTYPE_DATA_CFPOLL 0x02 +#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03 +#define WLAN_FSTYPE_NULL 0x04 +#define WLAN_FSTYPE_CFACK 0x05 +#define WLAN_FSTYPE_CFPOLL 0x06 +#define WLAN_FSTYPE_CFACK_CFPOLL 0x07 + +/*----------------------------------------------------------------*/ +/* Magic number, a quick test to see we're getting the desired struct */ + +#define P80211_IOCTL_MAGIC (0x4a2d464dUL) + +/*================================================================*/ +/* Types */ + +/*----------------------------------------------------------------*/ +/* A ptr to the following structure type is passed as the third */ +/* argument to the ioctl system call when issuing a request to */ +/* the p80211 module. */ + +typedef struct p80211ioctl_req +{ + char name[WLAN_DEVNAMELEN_MAX] __attribute__ ((packed)); + void *data __attribute__ ((packed)); + uint32_t magic __attribute__ ((packed)); + uint16_t len __attribute__ ((packed)); + uint32_t result __attribute__ ((packed)); +} __attribute__ ((packed)) p80211ioctl_req_t; struct orinoco_private { void *card; /* Pointer to card dependent structure */ @@ -116,6 +282,9 @@ /* Configuration dependent variables */ int port_type, createibss; int promiscuous, mc_count; + + uint16_t presniff_port_type; + uint16_t presniff_wepflags; }; #ifdef ORINOCO_DEBUG @@ -163,4 +332,12 @@ spin_unlock_irqrestore(&priv->lock, *flags); } +/*================================================================*/ +/* Function Declarations */ + +struct ieee802_11_hdr; + +void orinoco_int_rxmonitor( struct orinoco_private *dev, uint16_t rxfid, int len, + struct hermes_rx_descriptor *rxdesc, struct ieee802_11_hdr *hdr); + #endif /* _ORINOCO_H */ diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_cs.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_cs.c --- linux-2.6.2/drivers/net/wireless/orinoco_cs.c 2004-02-17 15:14:27.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_cs.c 2004-02-17 15:26:40.000000000 +0800 @@ -110,7 +110,7 @@ /* PCMCIA gumpf */ static void orinoco_cs_config(dev_link_t * link); -static void orinoco_cs_release(dev_link_t * link); +static void orinoco_cs_release(u_long arg); static int orinoco_cs_event(event_t event, int priority, event_callback_args_t * args); @@ -153,6 +153,24 @@ pcmcia_report_error(handle, &err); } + +/* Remove zombie instances (card removed, detach pending) */ +static void +flush_stale_links(void) +{ + dev_link_t *link, *next; + + TRACE_ENTER(""); + + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) { + orinoco_cs_detach(link); + } + } + TRACE_EXIT(""); +} + /* * This creates an "instance" of the driver, allocating local data * structures for one device. The device is registered with Card @@ -171,6 +189,9 @@ client_reg_t client_reg; int ret, i; + /* A bit of cleanup */ + flush_stale_links(); + dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); if (! dev) return NULL; @@ -181,6 +202,12 @@ link = &card->link; link->priv = dev; + /* Initialize the dev_link_t structure */ + /*init_timer(&link->release); + link->release.function = &orinoco_cs_release; + link->release.data = (u_long) link; + removed by Adrian 6-2-04 */ + /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; @@ -245,8 +272,13 @@ return; } - if (link->state & DEV_CONFIG) - orinoco_cs_release(link); + if (link->state & DEV_CONFIG) { + orinoco_cs_release((u_long)link); + if (link->state & DEV_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } /* Break the link with Card Services */ if (link->handle) @@ -260,7 +292,7 @@ dev); unregister_netdev(dev); } - free_netdev(dev); + kfree(dev); } /* orinoco_cs_detach */ /* @@ -498,7 +530,7 @@ orinoco_cs_error(link->handle, last_fn, last_ret); failed: - orinoco_cs_release(link); + orinoco_cs_release((u_long) link); } /* orinoco_cs_config */ /* @@ -507,8 +539,9 @@ * still open, this will be postponed until it is closed. */ static void -orinoco_cs_release(dev_link_t *link) +orinoco_cs_release(u_long arg) { + dev_link_t *link = (dev_link_t *) arg; struct net_device *dev = link->priv; struct orinoco_private *priv = dev->priv; unsigned long flags; diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_pci.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_pci.c --- linux-2.6.2/drivers/net/wireless/orinoco_pci.c 2004-02-17 15:14:27.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_pci.c 2004-02-17 15:26:40.000000000 +0800 @@ -223,7 +223,7 @@ printk(KERN_DEBUG "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n", - pci_name(pdev), dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); + pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); hermes_struct_init(&priv->hw, dev->base_addr, HERMES_MEM, HERMES_32BIT_REGSPACING); @@ -289,7 +289,7 @@ iounmap((unsigned char *) priv->hw.iobase); pci_set_drvdata(pdev, NULL); - free_netdev(dev); + kfree(dev); pci_disable_device(pdev); } @@ -359,8 +359,7 @@ return 0; } -static struct pci_device_id orinoco_pci_pci_id_table[] = { - {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, +static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = { {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_plx.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_plx.c --- linux-2.6.2/drivers/net/wireless/orinoco_plx.c 2003-12-18 10:59:45.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_plx.c 2004-02-17 15:26:40.000000000 +0800 @@ -236,7 +236,7 @@ printk(KERN_DEBUG "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n", - pci_name(pdev), pdev->irq, pccard_ioaddr); + pdev->slot_name, pdev->irq, pccard_ioaddr); hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, HERMES_16BIT_REGSPACING); @@ -291,7 +291,7 @@ pci_set_drvdata(pdev, NULL); - free_netdev(dev); + kfree(dev); release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); @@ -299,7 +299,7 @@ } -static struct pci_device_id orinoco_plx_pci_id_table[] = { +static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = { {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_tmd.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_tmd.c --- linux-2.6.2/drivers/net/wireless/orinoco_tmd.c 2003-12-18 10:58:16.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_tmd.c 2004-02-17 15:26:40.000000000 +0800 @@ -128,7 +128,7 @@ printk(KERN_DEBUG "Detected Orinoco/Prism2 TMD device at %s irq:%d, io addr:0x%lx\n", - pci_name(pdev), pdev->irq, pccard_ioaddr); + pdev->slot_name, pdev->irq, pccard_ioaddr); hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, HERMES_16BIT_REGSPACING); @@ -182,7 +182,7 @@ pci_set_drvdata(pdev, NULL); - free_netdev(dev); + kfree(dev); release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); @@ -190,7 +190,7 @@ } -static struct pci_device_id orinoco_tmd_pci_id_table[] = { +static struct pci_device_id orinoco_tmd_pci_id_table[] __devinitdata = { {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ {0,}, }; diff -Naur linux-2.6.2/drivers/net/wireless/userhermes.c linux-2.6.2-orinoco/drivers/net/wireless/userhermes.c --- linux-2.6.2/drivers/net/wireless/userhermes.c 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.2-orinoco/drivers/net/wireless/userhermes.c 2004-02-17 15:26:40.000000000 +0800 @@ -0,0 +1,477 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef __u8 u8; +typedef __u16 u16; +typedef __u32 u32; + +#include "hermes.h" + +#define BAP_BUSY_TIMEOUT (50) +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */ + +#define fatal(s) do { perror(s); exit(1); } while (0) + +typedef struct record_info { + u16 rid; + u16 len; + char *name; +} record_info_t; + +record_info_t rid_table[] = { + {0xfc00, 2, "CNFPORTTYPE"}, + {0xfc01, 6, "CNFOWNMACADDR"}, + {0xfc02, 34, "CNFDESIREDSSID"}, + {0xfc03, 2, "CNFOWNCHANNEL"}, + {0xfc04, 34, "CNFOWNSSID"}, + {0xfc05, 2, "CNFOWNATIMWIN"}, + {0xfc06, 0, "CNFSYSSCALE"}, + {0xfc07, 0, "CNFMAXDATALEN"}, + {0xfc08, 0, "CNFWDSADDR"}, + {0xfc09, 0, "CNFPMENABLED"}, + {0xfc0a, 0, "CNFPMEPS"}, + {0xfc0b, 0, "CNFMULTICASTRX"}, + {0xfc0c, 0, "CNFMAXSLEEPDUR"}, + {0xfc0d, 0, "CNFCNFPMHOLDDUR"}, + {0xfc0e, 0, "CNFOWNNAME"}, + {0xfc10, 0, "CNFOWNDTIMPER"}, + {0xfc11, 0, "CNFWDSADDR1"}, + {0xfc12, 0, "CNFWDSADDR2"}, + {0xfc13, 0, "CNFWDSADDR3"}, + {0xfc14, 0, "CNFWDSADDR4"}, + {0xfc15, 0, "CNFWDSADDR5"}, + {0xfc16, 0, "CNFWDSADDR6"}, + {0xfc17, 0, "CNFMCASTPMBUFF"}, + {0xfcb0, 0, "CNFSHORTPREAMBLE"} +}; + +#define NUM_RIDS (sizeof(rid_table) / sizeof(record_info_t)) + +typedef struct record { + u16 len; + u16 type; + u16 value[4096]; +} record_t; + + +/* Set up a BAP to read a particular chunk of data from card's internal buffer. + * + * Returns: < 0 on internal failure (errno), 0 on success, >0 on error from firmware + * + * Callable from any context */ +static int hermes_bap_seek(ulong hw, int bap, u16 id, u16 offset) +{ + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; + int k; + u16 reg; + + /* Paranoia.. */ + if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) + return -EINVAL; + + /* Now we actually set up the transfer */ + hermes_write_reg(hw, sreg, id); + hermes_write_reg(hw, oreg, offset); + /* Wait for the BAP to be ready */ + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ( (reg & HERMES_OFFSET_BUSY) && k) { + k--; + reg = hermes_read_reg(hw, oreg); + } + + if (reg & HERMES_OFFSET_BUSY) + return -ETIMEDOUT; + if (reg & HERMES_OFFSET_ERR) + return reg; + + return 0; +} + +/* Read a block of data from the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + * + * Callable from any context */ +int hermes_bap_pread(ulong hw, int bap, char *buf, u16 len, + u16 id, u16 offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + return err; + + /* Actually do the transfer */ + hermes_read_data(hw, dreg, buf, len/2); + + return 0; +} + +/* Write a block of data to the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + * + * Callable from any context */ +int hermes_bap_pwrite(ulong hw, int bap, const char *buf, u16 len, + u16 id, u16 offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + return err; + + /* Actually do the transfer */ + hermes_write_data(hw, dreg, buf, len/2); + + return 0; +} + +void usage(void) +{ + fprintf(stderr, "Usage: userprism [showrecords]\n"); + exit(1); +} + +char * +rl_gets (void) +{ + char * line; + + /* Get a line from the user. */ + line = readline ("> "); + + /* If the line has any text in it, save it on the history. */ + if (line && *line) + add_history (line); + + return (line); +} + +void display(unsigned long base) +{ +#define DREG(name) printf("%-16s: %04x\n", #name, inw(base + HERMES_##name)) + DREG(CMD); + DREG(PARAM0); + DREG(PARAM1); + DREG(PARAM2); + DREG(STATUS); + DREG(RESP0); + DREG(RESP1); + DREG(RESP2); + DREG(INFOFID); + DREG(RXFID); + DREG(ALLOCFID); + DREG(TXCOMPLFID); + DREG(SELECT0); + DREG(OFFSET0); + DREG(SELECT1); + DREG(OFFSET1); + + DREG(EVSTAT); + DREG(INTEN); + DREG(EVACK); + DREG(CONTROL); + DREG(SWSUPPORT0); + DREG(SWSUPPORT1); + DREG(SWSUPPORT2); + DREG(AUXPAGE); + DREG(AUXOFFSET); + DREG(AUXDATA); +#undef DREG +} + +#undef udelay +void udelay(ulong usec) { + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = 1000 * usec; + nanosleep(&ts, NULL); +} + +static int hermes_issue_cmd(ulong base, u16 cmd, u16 param0) +{ + int k = CMD_BUSY_TIMEOUT; + u16 reg; + + /* First wait for the command register to unbusy */ + reg = hermes_read_regn(base, CMD); + while ( (reg & HERMES_CMD_BUSY) && k ) { + k--; + udelay(1); + reg = hermes_read_regn(base, CMD); + } + if (reg & HERMES_CMD_BUSY) { + return -EBUSY; + } + + hermes_write_regn(base, PARAM2, 0); + hermes_write_regn(base, PARAM1, 0); + hermes_write_regn(base, PARAM0, param0); + hermes_write_regn(base, CMD, cmd); + + return 0; +} + +int hermes_docmd_wait(ulong base, u16 cmd, u16 parm0) +{ + int err; + int k; + u16 reg; + u16 status; + + err = hermes_issue_cmd(base, cmd, parm0); + if (err) { + return -EIO; + } + + reg = hermes_read_regn(base, EVSTAT); + k = CMD_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(base, EVSTAT); + } + + if (! (reg & HERMES_EV_CMD)) { + return -ETIMEDOUT; + } + + status = hermes_read_regn(base, STATUS); + + hermes_write_regn(base, EVACK, HERMES_EV_CMD); + + if (status & HERMES_STATUS_RESULT) + return -EIO; + + return 0; +} + +int read_lt(ulong base, int bap, u16 rid, record_t *rec) +{ + int err; + + err = hermes_docmd_wait(base, HERMES_CMD_ACCESS, rid); + if (err) { + fprintf(stderr, "Cannot access RID 0x%04x\n", rid); + return err; + } + + err = hermes_bap_pread(base, bap, (char *)rec, 4, rid, 0); + if (err) { + fprintf(stderr, "Error %d reading type/length\n", err); + return err; + } + + if (rid != rec->type) { + fprintf(stderr, "RID (0x%04x) doesn't match rec->type (0x%04x)\n", + rid, rec->type); + return -1; + } + + if (rec->len <= 1) { + fprintf(stderr, "Record too short, rec->len = %d\n", rec->len); + return err; + } + + /* Convert length to bytes */ + rec->len = 2 * (rec->len - 1); + + err = hermes_bap_pread(base, bap, (char *)&rec->value, rec->len, rid, 4); + if (err) { + fprintf(stderr, "Error %d reading value (%d bytes)\n", err, rec->len); + return err; + } + + return 0; +} + +void +show_records(unsigned long base) +{ + int i, j; + record_t rec; + + printf("%d records total.\n", NUM_RIDS); + for (i = 0; i < NUM_RIDS; i++) { + record_info_t *info = &rid_table[i]; + printf("Record %s [0x%04x]:", info->name, info->rid); + if (info->len) + printf(" expected length %04d\n", info->len); + else + printf("\n"); + + if (read_lt(base, 1, info->rid, &rec) != 0) + continue; + printf("Type 0x%04x, Len %04d: ", rec.type, rec.len); + for (j = 0; j < rec.len / 2; j++) + printf("%04x:", rec.value[j]); + printf("\n"); + } +} + +void +show_record(unsigned long base, u16 rid) +{ + record_t rec; + int j; + + if (read_lt(base, 1, rid, &rec) != 0) + return; + printf("RID 0x%04x: ", rid); + printf("type=0x%04x len=%04d value=", rec.type, rec.len); + for (j = 0; j < rec.len / 2; j++) + printf("%04x:", rec.value[j]); + printf("\n"); +} + +void do_line(unsigned long base, const char *line) +{ + char reg[100]; + int off; + int val; + int n; + + n = sscanf(line, "%s %i\n", reg, &val); + if (n < 1 || n > 2) { + fprintf(stderr, "?\n"); + return; + } + + if (strcasecmp(reg, "CMD") == 0) { + off = HERMES_CMD; + } else if (strcasecmp(reg, "PARAM0") == 0) { + off = HERMES_PARAM0; + } else if (strcasecmp(reg, "PARAM1") == 0) { + off = HERMES_PARAM1; + } else if (strcasecmp(reg, "PARAM2") == 0) { + off = HERMES_PARAM2; + } else if (strcasecmp(reg, "STATUS") == 0) { + off = HERMES_STATUS; + } else if (strcasecmp(reg, "RESP0") == 0) { + off = HERMES_RESP0; + } else if (strcasecmp(reg, "RESP1") == 0) { + off = HERMES_RESP1; + } else if (strcasecmp(reg, "RESP2") == 0) { + off = HERMES_RESP2; + } else if (strcasecmp(reg, "INFOFID") == 0) { + off = HERMES_INFOFID; + } else if (strcasecmp(reg, "RXFID") == 0) { + off = HERMES_RXFID; + } else if (strcasecmp(reg, "ALLOCFID") == 0) { + off = HERMES_ALLOCFID; + } else if (strcasecmp(reg, "TXCOMPLFID") == 0) { + off = HERMES_TXCOMPLFID; + } else if (strcasecmp(reg, "SELECT0") == 0) { + off = HERMES_SELECT0; + } else if (strcasecmp(reg, "OFFSET0") == 0) { + off = HERMES_OFFSET0; + } else if (strcasecmp(reg, "DATA0") == 0) { + off = HERMES_DATA0; + } else if (strcasecmp(reg, "SELECT1") == 0) { + off = HERMES_SELECT1; + } else if (strcasecmp(reg, "OFFSET1") == 0) { + off = HERMES_OFFSET1; + } else if (strcasecmp(reg, "DATA1") == 0) { + off = HERMES_DATA1; + } else if (strcasecmp(reg, "EVSTAT") == 0) { + off = HERMES_EVSTAT; + } else if (strcasecmp(reg, "INTEN") == 0) { + off = HERMES_INTEN; + } else if (strcasecmp(reg, "EVACK") == 0) { + off = HERMES_EVACK; + } else if (strcasecmp(reg, "CONTROL") == 0) { + off = HERMES_CONTROL; + } else if (strcasecmp(reg, "SWSUPPORT0") == 0) { + off = HERMES_SWSUPPORT0; + } else if (strcasecmp(reg, "SWSUPPORT1") == 0) { + off = HERMES_SWSUPPORT1; + } else if (strcasecmp(reg, "SWSUPPORT2") == 0) { + off = HERMES_SWSUPPORT2; + } else if (strcasecmp(reg, "AUXPAGE") == 0) { + off = HERMES_AUXPAGE; + } else if (strcasecmp(reg, "AUXOFFSET") == 0) { + off = HERMES_AUXOFFSET; + } else if (strcasecmp(reg, "AUXDATA") == 0) { + off = HERMES_AUXDATA; + } else if (strcasecmp(reg, ".") == 0) { + display(base); + return; + } else if (strcasecmp(reg, ",") == 0) { + if (n != 2) { + fprintf(stderr, "? No FID given\n"); + return; + } + show_record(base, val); + return; + } else { + fprintf(stderr, "? Unknown register \"%s\"\n", reg); + return; + } + + if (n == 2) { + printf("0x%04x -> 0x%04x\n", val, (int)base+off); + outw(val, base+off); + } + printf("%s (0x%04x) = 0x%04x\n", reg, off, inw(base+off)); +} + +int +main(int argc, char *argv[]) +{ + char *e; + unsigned long base; + int err; + char * line; + + if (argc < 2) + usage(); + + base = strtol(argv[1], &e, 0); + if (*e) + usage(); + + err = ioperm(base, 0x40, 1); + if (err != 0) + fatal("ioperm"); + + if (argc > 2) { + show_records(base); + exit(0); + } + + + while (1) { + line = rl_gets(); + + if (! line) + break; + + do_line(base, line); + + free(line); + }; + + + exit(0); +}